package com.sea.base.vm

import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sea.base.ext.obs.smartPost
import kotlinx.coroutines.CoroutineScope

open class BaseViewModel : ViewModel() {
    /**
     * 默认的加载状态监听，页面大部分情况下至少有一个，所以写在了默认里
     */
    protected val _defLoadingState = MutableLiveData<UiNetStateData>()
    val defLoadingState: LiveData<UiNetStateData> = _defLoadingState

    /**
     * 默认启动，适合无Loading功能的接口
     */
    protected fun launchDef(tag: String, @MainThread block: suspend CoroutineScope.() -> Unit) =
        launch(tag, createDefLoadingFun(), block)

    /**
     * 发送LiveData接口状态的启动，大部分接口都使用该方式
     */
    protected fun launchLiveData(
        tag: String,
        uiState: UiState,
        ld: MutableLiveData<UiNetStateData> = _defLoadingState,
        @MainThread block: suspend CoroutineScope.() -> Unit
    ) =
        launch(tag, createLiveDataLoadingFun(uiState, ld), block)

    /**
     * 启动基于vm生命周期的协程，可监听接口状态[state]
     * @param tag 只是接口描述，没其他作用
     * @param state 接口加载状态回调，[createDefLoadingFun]、[createLiveDataLoadingFun]
     * @param block 主线程协程
     */
    fun launch(tag: String, @MainThread state: (NetStateData) -> Unit, @MainThread block: suspend CoroutineScope.() -> Unit) =
        viewModelScope.netLaunch(tag, state, block)

    protected fun createLiveDataLoadingFun(
        uiState: UiState,
        ld: MutableLiveData<UiNetStateData> = _defLoadingState,
    ) = createLiveDataLoadingFun(uiState, ld) { false }

    /**
     * 发送到LiveData的Loading
     * @param ld 可自己创建一个LiveData接收
     * @param intercept 如果不需要默认操作可自行拦截
     * 注意：如果返回true，你必须处理这个消息，比如重新发送[ld]
     *
     * @return 传入[launch]的回调
     */
    protected inline fun createLiveDataLoadingFun(
        uiState: UiState,
        ld: MutableLiveData<UiNetStateData> = _defLoadingState,
        crossinline intercept: (NetStateData) -> Boolean,
    ) = createDefLoadingFun {
        val isIntercept = intercept.invoke(it)
        if (!isIntercept) {
            ld.smartPost(UiNetStateData(uiState, it))
        }
        isIntercept
    }

    /**
     * 强制让当前ui状态变为空样式
     */
    fun forceSendEmptyEvent(ld: MutableLiveData<UiNetStateData> = _defLoadingState) {
        ld.smartPost(UiNetStateData(if (ld.value?.uiState == UiState.INIT) UiState.INIT else UiState.REFRESH, NetState.EMPTY, "强制刷新为空", null))
    }
}
